import Flutter
import UIKit

public class JieliBleOtaPlugin: NSObject, FlutterPlugin {

    // methods
    static let methodStart2Ota = "inmotion://jieli_ota/method_start_to_ota";
    static let methodRequestDeviceFirmwareState = "inmotion://jieli_ota/method_request_fw_state";
    static let methodNotifyDataReceived = "inmotion://jieli_ota/method_on_msg_received";
    static let methodNotifyConnected = "inmotion://jieli_ota/method_on_link_connected";
    static let methodNotifyDisconnected = "inmotion://jieli_ota/method_on_link_disconnected";

    // callbacks
    static let cbWriteData = "inmotion://cb/write_data";
    static let cbDisconnectLink = "inmotion://cb/link/disconnect";
    static let cbConnectLink = "inmotion://cb/link/connect";
    static let cbOnOtaProgressChanged = "inmotion://cb/on_ota_progress_changed";
    static let cbOnDeviceFirmwareStatusRequested = "inmotion://cb/on_device_firmware_status_requested";
    static let cbOnDeviceFirmwareStatusRequestFailed = "inmotion://cb/on_device_firmware_status_request_failed";
    static let cbOnOtaUpdateSuccess = "inmotion://cb/on_ota_update_success";
    static let cbOnOtaUpdateFailed = "inmotion://cb/on_ota_update_failed";
    
    
    public static func register(with registrar: FlutterPluginRegistrar) {
        let channel = FlutterMethodChannel(name: "jieli_ble_ota_plugin", binaryMessenger: registrar.messenger())
        let instance = JieliBleOtaPlugin(channel: channel)
        registrar.addMethodCallDelegate(instance, channel: channel)
    }

    private let channel: FlutterMethodChannel;
    private let otaManager: JieliOtaManager;

    // constructor
    init(channel: FlutterMethodChannel) {
        self.channel = channel;
        self.otaManager = JieliOtaManager();
        super.init()
        
        otaManager.setPluginInstace(plugin: self);
    }

    public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
        print("handle method call, method:"+call.method);
        switch call.method {
            case JieliBleOtaPlugin.methodNotifyConnected:
                print("Notify reconnected");
                let param = call.arguments as! [String: Any];
                let identifier = param["identifier"];
                let name = param["name"];
            
                onLinkConnected(identifier: param["identifier"] as! String, name: param["name"] as! String);
            
            case JieliBleOtaPlugin.methodNotifyDisconnected:
                onLinkDisconnected();
            
            case JieliBleOtaPlugin.methodRequestDeviceFirmwareState :
                requestDeviceFirmwareState();
            
            case JieliBleOtaPlugin.methodStart2Ota :
                start2Ota(filePath: call.arguments as! String );
            
            case JieliBleOtaPlugin.methodNotifyDataReceived :
                onDataReceived(bytes: (call.arguments as! FlutterStandardTypedData).data);
                
            default :
                print("Unknown method call [" + call.method + "].")
                result("Unknown method call [" + call.method + "].")
        }
    }

    private func requestDeviceFirmwareState() {
        otaManager.requestDeviceFirmwareState();
    }

    private func start2Ota(filePath: String) {
        otaManager.reset();
        otaManager.start2Ota(filePath: filePath);
    }

    // 通知 SDK 收到数据
    private func onDataReceived(bytes: Data) {
        otaManager.onDataReceived(bytes: bytes);
    }

    // 通知 SDK 设备已连接
    private func onLinkConnected(identifier: String, name: String){
        otaManager.onConnected(identifier: identifier, name: name);
    }
    
    // 通知 SDK 设备连接已断开
    private func onLinkDisconnected() {
        otaManager.onDisconnected();
    }
    

    // 通知 Flutter 层发送数据
    public func writeData(bytes: Data) {
        channel.invokeMethod(JieliBleOtaPlugin.cbWriteData, arguments: ["bytes": bytes])
    }

    // 通知 Flutter 层升级进度更新
    public func notifyOtaProgressChanged(type: Int, progress: Float) {
        channel.invokeMethod(JieliBleOtaPlugin.cbOnOtaProgressChanged, arguments:  ["type": type, "progress": progress]);
    }

    // 通知 Flutter 层设备固件状态回复
    public func notifyDeviceFirmwareStatusRequested(firmwareBroken: Bool) {
        channel.invokeMethod(JieliBleOtaPlugin.cbOnDeviceFirmwareStatusRequested, arguments: ["is_firmware_broken": firmwareBroken]);
    }
    
    // 通知 Flutter 层请求设备固件状态失败
    public func notifyDeviceFirmwareStatusRequestFailed() {
        channel.invokeMethod(JieliBleOtaPlugin.cbOnDeviceFirmwareStatusRequestFailed, arguments: ["error_code": 99999]);
    }
                                                                                    
    // 通知 Flutter 层设备升级成功
    public func notifyOtaUpdateSuccess() {
        channel.invokeMethod(JieliBleOtaPlugin.cbOnOtaUpdateSuccess, arguments: []);
    }
    
    // 通知 Flutter 层设备升级失败
    public func notifyOtaUpdateFailed(code: String) {
        channel.invokeMethod(JieliBleOtaPlugin.cbOnOtaUpdateFailed, arguments: ["error_code": code]);
    }

    // 通知 Flutter 断开连接 
    public func disconnectLink() {
        channel.invokeMethod(JieliBleOtaPlugin.cbDisconnectLink, arguments: []);
    }

    // 通知 Flutter 重连
    public func connectLink() {
        channel.invokeMethod(JieliBleOtaPlugin.cbConnectLink, arguments: []);
    }
    
}
